/**
 * @author Ming & Tony
 * Operator.java
 * Represents a binary or unary operator.
 */
package calculator;

public class Operator {

    //operators are listed based on priority operators[priority][operators with the same priority]
    final static String[][] operators = {
        {"(", ")"},
        {"E"},
        {"log", "ln", "sin", "sinh", "asin", "cos", "cosh", "acos", "tan", "tanh", "atan", "^"},
        {"*", "/"},
        {"+", "-"}
    };

    //multiply the result to the number to the left in the equation ie. 2log5 = 2*log 5
    final static boolean[][] operatorLeftMultipliable = {
        {true, false},
        {false},
        {true, true, true, true, true, true, true, true, true, true, true, false},
        {false, false},
        {false, false}
    };
    final static int LONGEST_OPERATOR_LENGTH = Operator.initLongestOperatorLength();
    int priority = 0; //priority of operator during the evaluation process
    String operator = ""; //Operator.toString()

    /*
     * Constructor
     */
    Operator(Token operatorToken) {
        this.operator = operatorToken.toString();
        boolean found = false;
        for (int currPriority = 0; currPriority < Operator.operators.length; currPriority++) {
            for (int currOperator = 0; currOperator < Operator.operators[currPriority].length; currOperator++) {
                if (Operator.operators[currPriority][currOperator].equals(operator)) {
                    this.priority = currPriority;
                    found = true;
                    break;
                }
            }
            if (found) {
                break;
            }
        }
    }

    /**
     * @param operator
     * the operator to check if it exists
     *
     * @return
     * true if the operator parameter is a valid operator (ie. exist within the String[][] of operators)
     */
    static boolean operatorExists(String operator) {
        if (operator.equals("(") || operator.equals(")")) {
            return true;
        }
        for (int priority = 0; priority < operators.length; priority++) {
            for (int currOperator = 0; currOperator < operators[priority].length; currOperator++) {
                if (operator.equalsIgnoreCase(operators[priority][currOperator])) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * @param operator
     * the operator currently being evaluated
     *
     * @return
     * true if the number in front of the operator (to the left) should be multiplied by the evaluated operator
     * (ie. the operator "log" will be true because in the expression: 3log5, the 3 (in front of log) should be multiplied to log5)
     * during the evaluation process, there is no other means of indicating a multiplication (ie. the multiplication sign is not present)
     */
    static boolean isLeftMultipliable(String operator) {
        for (int priority = 0; priority < operators.length; priority++) {
            for (int currOperator = 0; currOperator < operators[priority].length; currOperator++) {
                if (operator.equalsIgnoreCase(operators[priority][currOperator])) {
                    return operatorLeftMultipliable[priority][currOperator];
                }
            }
        }
        return false;
    }

    /**
     * this method calculates the longest length and stores the longest length in the constant "LONGEST_OPERATOR_LENGTH"
     * So use Operator.getLongestOperatorLength() to retrieve the longest length of all operators
     * (this value is used by tokenizer)
     */
    static final int initLongestOperatorLength() {
        int longestLength = -1;
        for (int priority = 0; priority < Operator.operators.length; priority++) {
            for (int operatorIndex = 0; operatorIndex < Operator.operators[priority].length; operatorIndex++) {
                if (Operator.operators[priority][operatorIndex].length() > longestLength) {
                    longestLength = Operator.operators[priority][operatorIndex].length();
                }
            }
        }
        return longestLength;
    }

    /**
     *
     * @return the length of the longest operator (this parameter is used by tokenizer)
     */
    static final int getLongestOperatorLength() {
        return Operator.LONGEST_OPERATOR_LENGTH;
    }

    /**
     * @return the priority of operator during the evaluation process
     */
    int getPriority() {
        return this.priority;
    }

    @Override
    public String toString() {
        return this.operator;
    }
}
